home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / c / library / dos / communic / pcmail / main / gtrans.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  10.3 KB  |  340 lines

  1. /*++
  2. /* NAME
  3. /*    gtrans 3
  4. /* SUMMARY
  5. /*    g protocol strategy functions
  6. /* PROJECT
  7. /*    pc-mail
  8. /* PACKAGE
  9. /*    cico
  10. /* SYNOPSIS
  11. /*    #include "gp.h"
  12. /*
  13. /*    int ginit(fd)
  14. /*    int fd;
  15. /*
  16. /*    Packet *galloc()
  17. /*
  18. /*    void gsproto(fd,pk)
  19. /*    int fd;
  20. /*    Packet *pk;
  21. /*
  22. /*    Packet *grproto(fd)
  23. /*    int fd;
  24. /*
  25. /*    void gfree(pk)
  26. /*    Packet *pk;
  27. /*
  28. /*    int gfinit(fd)
  29. /*    int fd;
  30. /* DESCRIPTION
  31. /*    ginit() exchanges the initial g protocol messages and allocates
  32. /*    memory for packet buffers.
  33. /*
  34. /*    galloc() returns a pointer to a free packet, after filling
  35. /*    in its k and len fields. This packet is supposed to be filled
  36. /*    with data, and to be subsequently queued with gsproto().
  37. /*
  38. /*    grproto() extracts the next packet from the input queue.
  39. /*    The packet should be returned to the free pool with gfree().
  40. /*
  41. /*    gfinit() sends protocol termination messages until it receives one
  42. /*    or until it gets bored.
  43. /* FUNCTIONS AND MACROS
  44. /*    gsctrl(), gsdata(), grpack(), gfail()
  45. /* DIAGNOSTICS
  46. /*    ginit(), gfinit() return a nonzero value if there was a problem.
  47. /*
  48. /*    The other functions return through a call of gfail() in case of
  49. /*    unrecoverable problems.
  50. /* BUGS
  51. /*    Window size is equal to one. This implies that the program 
  52. /*    only sends new data when the previous packet was acknowledged.
  53. /*    However, only the functions in *this* module need to be adapted 
  54. /*    to accomodate larger transmission window sizes.
  55. /* AUTHOR(S)
  56. /*    W.Z. Venema
  57. /*    Eindhoven University of Technology
  58. /*    Department of Mathematics and Computer Science
  59. /*    Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  60. /* CREATION DATE
  61. /*    Sun Apr 19 17:30:08 GMT+1:00 1987
  62. /* LAST MODIFICATION
  63. /*    90/01/22 13:01:44
  64. /* VERSION/RELEASE
  65. /*    2.1
  66. /*--*/
  67.  
  68. #include "gp.h"
  69.  
  70. /*
  71. * "The protocol is defined in terms of message transmissions of 8-bit bytes."
  72. * "Each message includes one control byte plus a data segment of zero or more"
  73. * "information bytes. The allowed data segment sizes range between 32 and"
  74. * "4096 as determined by the formula 32*2^k where k is a 3-bit number."
  75. */
  76.  
  77. int seglen[] = {             /* data segment sizes */
  78.     1,32,64,128,256,512,1024,2048,4096,
  79. };
  80.  
  81. static int sndseg;            /* data segment k-value they want */
  82. static int sndlen;            /* data segment length they want */
  83. static int sndwin;            /* transmission window size they want */
  84.  
  85. #define ourseg    2            /* data segment k-value we want */
  86. #define ourlen    64            /* data segment length we want */
  87. #define ourwin    1            /* transmission window size we want */
  88.  
  89. static Packet *inpk = 0;        /* receive packet "pool" */
  90. static Packet *outpk = 0;        /* send packet "pool" */
  91.  
  92. static int rval = 0;            /* our R value */
  93. static int sval = 1;            /* our S value */
  94.  
  95. /*
  96. * "Initial synchronization is accomplished with two 3-way handshakes:"
  97. * "two each of INITA/INITB/INITC. Each sender transmits INITA messages"
  98. * "repeatedly. When an INITA message is received, INITB is sent in return."
  99. * "When an INITB message is received *and* an INITB message has been sent,"
  100. * "an INITC message is sent. The INITA and INITB messages carry with them"
  101. * "the packet and window size that each receiver wants to use, and the"
  102. * "senders are supposed to comply. When a receiver has seen all three INIT"
  103. * "messages, the channel is considered to be open. (...) the INIT messages"
  104. * "are ignored elsewhere. (...)"
  105. * "After initial synchronization each receiver sets a modulo-8"
  106. * "incrementing counter R to 0; each sender sets a similar counter S to 1."
  107. * "The value of R is always the number of the most recent correctly received"
  108. * "packet. The value of S is always the first sequence number in the output"
  109. * "window."
  110. *
  111. * Since INIT messages are ignored once the channel has been opened, we
  112. * set the initial values of R and S at compile time.
  113. */
  114.  
  115. /* ginit - g-protocol start-up */
  116.  
  117. int ginit(fd)
  118. int fd;
  119. {
  120.     register int state = 0;
  121.     register int next = 0;
  122.     int count = 0;
  123.  
  124.     /* set up receive packet buffers */
  125.  
  126.     if ((inpk = (Packet *) malloc((unsigned)sizeof(Packet)+ourlen)) == 0) {
  127.     DEBUG(7,"gopen: malloc failed\n","");
  128.     return(FAIL);
  129.     }
  130.  
  131.     /* 
  132.     * Very simple automaton for initial message exchanges.
  133.     * We send a packet, receive a packet and so on. The
  134.     * automaton terminates when it reaches its accepting state,
  135.     * when a time-out error occurs, or when it seems to get
  136.     * stuck in one state.
  137.     */
  138.  
  139.     while (state != INITC) {
  140.  
  141.     /* select action to be done in this state */
  142.  
  143.     switch (state) {
  144.     case 0:                    /* initial state */
  145.         gsctrl(fd,INITA|IFLD(ourwin));    /* send INITA message */
  146.         break;
  147.     case INITA:                /* we received INITA */
  148.         gsctrl(fd,INITB|IFLD(ourseg-1));    /* send INITB in response */
  149.         break;
  150.     case INITB:                /* we received INITB */
  151.         gsctrl(fd,INITC|IFLD(ourwin));    /* assume we sent INITB */
  152.         break;
  153.     }
  154.  
  155.     /*
  156.     * Transition part of the automaton. Receive a packet and process
  157.     * its contents. Depending on the packet and the current state
  158.     * select a new state. Stay in the current state when a corrupted 
  159.     * packet is received or when we receive an unexpected packet.
  160.     * If no packet is received assume we have lost contact and terminate.
  161.     */
  162.  
  163.     switch (next = grpack(fd,inpk)) {    /* see what we get */
  164.     case INITA:
  165.         sndwin = IVAL(inpk->c);        /* transmission window size */
  166.         state = next;
  167.         break;
  168.     case INITB:
  169.         sndseg = IVAL(inpk->c)+1;        /* send-segment type */
  170.         sndlen = seglen[sndseg];        /* send-segment length */
  171.         state = (state == INITA ? next : state);
  172.         break;
  173.     case INITC:
  174.         state = (state == INITB ? next : state);
  175.         break;
  176.     case FAIL:                /* corrupted message received */
  177.         break;
  178.     case TIME:                /* no message received */
  179.         return(FAIL);
  180.     }
  181.  
  182.     /* check we don't stay in the same state forever */
  183.  
  184.     if (state == next) {
  185.         count = 0;
  186.     } else if (count++ > MAXTRY) {
  187.         return(FAIL);
  188.     }
  189.     }
  190.  
  191.     /* set up transmission buffer "pool" */
  192.  
  193.     if ((outpk = (Packet *) malloc((unsigned)sizeof(Packet)+sndlen)) == 0) {
  194.     DEBUG(7,"gopen: malloc failed\n","");
  195.     return(FAIL);
  196.     }
  197.     return(0);
  198. }
  199.  
  200. /*
  201. * The current version used a window size of 1, i.e. no further data
  202. * transmissions until the last transmitted data have been acknowledged.
  203. * The following routines anticipate on future versions with a real pool of
  204. * transmit and receive buffers.
  205. */
  206.  
  207. /* galloc - allocate send packet, fill in size info */
  208.  
  209. Packet *galloc()
  210. {
  211.     register Packet *pk = outpk;
  212.  
  213.     pk->k = sndseg;                /* data segment type */
  214.     pk->len = sndlen;                /* data segment size */
  215.     return(pk);
  216. }
  217.  
  218. /* gfree - release receive packet */
  219.  
  220. void gfree(pk)
  221. register Packet *pk;
  222. {
  223.     /* this function intentionally left blank */
  224. }
  225.  
  226. /*
  227. * The central part of the protocol is in the routines gsproto() and
  228. * grproto(). These are the functions that negotiate with the other
  229. * host about what data to (re)transmit and to (n)ack.
  230. * Major changes are to be expected here when larger transmission
  231. * window sizes are to be supported.
  232. */
  233.  
  234. /* gsproto - queue one packet for transmission */
  235.  
  236. void gsproto(fd,pk)
  237. int fd;
  238. Packet *pk;
  239. {
  240.     int numtry = 0;                /* retry count */
  241.  
  242.     gsdata(fd,pk,SFLD(sval)|RFLD(rval));    /* send data packet */
  243.  
  244.     inpk->k = ourseg;                /* "allocate" receive packet */
  245.     inpk->len = ourlen;
  246.  
  247.     while (numtry < MAXTRY) {
  248.     switch (grpack(fd,inpk)) {        /* what is the reply */
  249.     case SHORT:                /* SHORT DATA */
  250.     case DATA:                /* LONG DATA */
  251.         gsctrl(fd,RJ|RFLD(rval));        /* not now please */
  252.     case RJ:                               /* REJECT */
  253.     case RR:                               /* RECEIVER READY */
  254.         if (RVAL(inpk->c) == sval) {    /* check their R value */
  255.         sval = (sval+1)&07;        /* update our S value */
  256.         return;
  257.         }
  258.     case FAIL:                /* bad packet received */
  259.     case TIME:                /* no packet received */
  260.         gsdata(fd,pk,SFLD(sval)|RFLD(rval));/* send data packet again */
  261.         numtry++;                /* but not forever */
  262.         break;
  263.     case CLOSE:
  264.         gfail();                /* surprise! */
  265.         /* NOTREACHED */
  266.     }
  267.     }
  268.     gfail();                        /* too may retries, abort */
  269.     /* NOTREACHED */
  270. }
  271.  
  272. /* grproto - take one packet from input queue */
  273.  
  274. Packet *grproto(fd)
  275. int fd;
  276. {
  277.     int numtry = 0;                /* retry count */
  278.     int xpct = (rval+1)&07;            /* expected sequence nr */
  279.     register Packet *pk = inpk;            /* take one from the "pool" */
  280.  
  281.     pk->k = ourseg;                /* initialize receive packet */
  282.     pk->len = ourlen;
  283.  
  284.     while (numtry < MAXTRY) {            /* don't loop forever */
  285.     switch (grpack(fd,pk)) {        /* see what we got */
  286.     case DATA:                /* LONG DATA */
  287.     case SHORT:                /* SHORT DATA */
  288.         if (SVAL(pk->c) == xpct) {        /* you're the 1 that I want */
  289.         gsctrl(fd,RR|RFLD(rval = xpct));/* update R and acknowledge */
  290.         return(pk);            /* we are done here */
  291.         }                    /* else ignore the packet */
  292.     case FAIL:                /* bad packet */
  293.         gsctrl(fd,RJ|RFLD(rval));        /* reset their S value */
  294.     case TIME:                /* no packet, no nak */
  295.         numtry++;                /* don't loop forever */
  296.         break;                /* read another packet */
  297.     case RR:                /* RECEIVER READY */
  298.     case RJ:                /* REJECT */
  299.         break;                /* ignore */
  300.     case CLOSE:                /* surprise! */
  301.         gfail();                /* boy, am I confused */
  302.         /* NOTREACHED */
  303.     }
  304.     }
  305.     gfail();                        /* too may retries, abort */
  306.     /* NOTREACHED */
  307. }
  308.  
  309. /*
  310. * "The CLOSE message is used to terminate communications. Software on"
  311. * "either or both ends of the communication channel may initiate"
  312. * "termination. In any case when one end wants to terminate it sends"
  313. * "CLOSE messages until one is received from the other end or until a"
  314. * "programmable limit on the number of CLOSE messages is reached. Receipt"
  315. * "of a CLOSE message causes a CLOSE message to be sent."
  316. *
  317. * Normally systems decide together when to turn off the protocol so
  318. * that each system will start sending CLOSE messages at the same time.
  319. *
  320. * When a CLOSE message is received in the middle of a conversation
  321. * a protocol error is generated in grproto() or gsproto(). Then
  322. * gfinit() is called, so that the other system still sees a few CLOSE
  323. * messages.
  324. */
  325.  
  326. /* gfinit - shut down the g protocol */
  327.  
  328. int gfinit(fd)
  329. int fd;
  330. {
  331.     register int numtry;
  332.  
  333.     for (numtry = 0; numtry < MAXTRY; numtry++) {    /* programmable limit */
  334.     gsctrl(fd,CLOSE);                /* send CLOSE message */
  335.     if (grpack(fd,inpk) == CLOSE)            /* hope for same */
  336.         return(0);                    /* got it */
  337.     }
  338.     return(FAIL);                    /* no CLOSE received */
  339. }
  340.